package com.dustedpixels.jasmin.memory.impl;

import com.dustedpixels.jasmin.memory.Memory16x8;
import com.dustedpixels.jasmin.memory.implbase.Memory16x8ImplBase;

public final class SelectMemory16x8 extends Memory16x8ImplBase {
    private final short selectorMask;
    private final short addressMask;
    private final int selectorShift;
    private final Memory16x8[] memories;

    public static SelectMemory16x8 create(int selectorBits, Memory16x8[] memories) {
        if (selectorBits > 16 || selectorBits < 0) {
            throw new IllegalArgumentException("Selector bits must be in 0..16 range.");
        }
        
        int memoriesCount = 1 << selectorBits;
        
        if (memories.length != memoriesCount) {
            throw new IllegalArgumentException(
                    "The length of the memories array should be " 
                    + memoriesCount);
        }
        
        int selectorShift = 16 - selectorBits;
        short addressMask = (short) ((1 << selectorShift) - 1);
        short selectorMask = (short) ~addressMask;
        
        return new SelectMemory16x8(addressMask,
                selectorMask,
                selectorShift,
                memories);
    }
    
    SelectMemory16x8(short addressMask,
            short selectorMask,
            int selectorShift, 
            Memory16x8[] memories) {
        this.selectorMask = selectorMask;
        this.addressMask = addressMask;
        this.selectorShift = selectorShift;
        this.memories = memories;
    }
    
    public byte peek(short address) {
        return getMemory(address).peek((short) (address & addressMask));
    }

    public void poke(short address, byte value) {
        getMemory(address).poke((short) (address & addressMask), value);
    }
    
    private Memory16x8 getMemory(short address) {
        return memories[(address & selectorMask) >>> selectorShift];
    }
}
